//
// Copyright (c) 2014, 保留所有权利。
//
// AgentSync.java
//
// 作    者：王红燕
// 当前版本：1.0
// 2014 上午9:15:28
//
// 
//
package com.vanke.agent.sync;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.log4j.Logger;
import org.wang.hongyan.common.lock.LockContext;

import com.vanke.agent.ADataSource;
import com.vanke.agent.C;
import com.vanke.agent.Cfg;
import com.vanke.agent.bean.Module;
import com.vanke.agent.bean.RoomInfo;
import com.vanke.agent.common.AvoidDisturb;
import com.vanke.agent.common.Util;
import com.vanke.agent.sync.copy.BizParamOptionSync;
import com.vanke.agent.sync.copy.CqServiceProcSync;
import com.vanke.agent.sync.copy.CqServiceSync;
import com.vanke.agent.sync.copy.CstAttachSync;
import com.vanke.agent.sync.copy.FeeSync;
import com.vanke.agent.sync.copy.SaleServiceProcSync;
import com.vanke.agent.sync.copy.SaleServicetSync;
import com.vanke.agent.tools.MonitorClient;

/**
 *
 */
public class AgentSync extends AgentContext {
	protected static boolean pause  = false;
	private static Logger log = Logger.getLogger(AgentSync.class);

	protected DateFormat dateFormat = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss.S");
	protected DateFormat shortFormat = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");
	protected DateFormat dateDF = new SimpleDateFormat("yyyy-MM-dd");

	protected String syncLabel = C.DC_MODULE_KEY;

	public static void main(String[] args) {
		//new AgentSync().doSync();
		AgentSync as = new AgentSync();
		if (args.length == 2) {
			if (!"-s".equals(args[0])) {
				System.out.println("unknown command:" + args[0]);
				return;
			}
			as.singleSync(args[1]);
		} else {			
			as.doSync();
		}
	}

	private static Module getModule(String key) {
		Connection con = ADataSource.getConnection(ADataSource.SCHEMA_BIZ);
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select ModuleKey,ModuleName,Host,Pid,Status from sys_Monitor where `ModuleKey`=?";
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, key);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				Module m = new Module();
				m.setKey(rs.getString(1));
				m.setName(rs.getString(2));
				m.setHost(rs.getString(3));
				m.setPid(rs.getString(4));
				m.setStatus(rs.getString(5));
				return m;
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("获取模块信息失败");
		} finally {
			ADataSource.close(rs, pstmt, con);
		}
		return null;
	}

	void loadConfig() {
		try {
			intervalIntime = Long.parseLong(Cfg.get("sync.interval.intime"));
			intervalIntime *= 60 * 1000;
		} catch (Exception e) {
			e.printStackTrace();
			AgentContext.exit("初始化配置异常[" + Util.formatStackTrace(e) + "]");
		}
		try {
			parseSyncTime();
		} catch (Exception e) {
			e.printStackTrace();
			AgentContext.exit("初始化配置异常[" + Util.formatStackTrace(e) + "]");
		}
		bookingCfg.cfgKey = "import.booking.addition.time";
		String s = Cfg.get(bookingCfg.cfgKey);
		if ((bookingCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse booking begin time [" + s + "] fail!");
		}

		orderCfg.cfgKey = "import.order.addition.time";
		s = Cfg.get(orderCfg.cfgKey);
		if ((orderCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse order begin time [" + s + "] fail!");
		}

		contractCfg.cfgKey = "import.contract.addition.time";
		s = Cfg.get(contractCfg.cfgKey);
		if ((contractCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse contract begin time [" + s + "] fail!");
		}

		saleServiceCfg.cfgKey = "import.saleService.addition.time";
		s = Cfg.get(saleServiceCfg.cfgKey);
		if ((saleServiceCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse saleService begin time [" + s + "] fail!");
		}
		getinCfg.cfgKey = "import.getin.addition.time";
		s = Cfg.get(getinCfg.cfgKey);
		if ((getinCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse getin begin time [" + s + "] fail!");
		}
		opportunityCfg.cfgKey = "import.opportunity.addition.time";
		s = Cfg.get(opportunityCfg.cfgKey);
		if ((opportunityCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse opportunity begin time [" + s + "] fail!");
		}

		pointCfg.cfgKey = "import.point.addition.time";
		s = Cfg.get(pointCfg.cfgKey);
		if ((pointCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse point begin time [" + s + "] fail!");
		}

		memberCfg.cfgKey = "import.member.addition.time";
		s = Cfg.get(memberCfg.cfgKey);
		if ((memberCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse member begin time [" + s + "] fail!");
		}

		receiveCfg.cfgKey = "import.receive.addition.time";
		s = Cfg.get(receiveCfg.cfgKey);
		if ((receiveCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse receive begin time [" + s + "] fail!");
		}

		customerCfg.cfgKey = "import.customer.created.time";
		s = Cfg.get(customerCfg.cfgKey);
		if ((customerCfg.beginTime = parseTime(s)) == null) {
			AgentContext.exit("parse customer begin time [" + s + "] fail!");
		}

		customerCfg.cfgKey = "import.customer.modify.time";
		s = Cfg.get(customerCfg.cfgKey);
		if ((customerCfg.modifyTime = parseTime(s)) == null) {
			AgentContext.exit("parse customer modifyTime [" + s + "] fail!");
		}
		log.info("同步配置");
		log.info(C.SPLIT_LINE);
		log.info("周期同步频率：" + (intervalIntime / 60000) + "分钟");
		log.info("每日同步窗口：" + Cfg.get("sync.begin") + "~" + Cfg.get("sync.end"));
		log.info("序列号服务器：" + Cfg.get("series.server.thrift.addr") + ":"
				+ Cfg.get("series.server.thrift.port"));
		log.info("消息队列服务：" + Cfg.get("mq.addr") + "/"
				+ Cfg.get("jms.destination"));
		log.info(C.SPLIT_LINE);
		log.info("同步开始时间点");
		log.info("客户：" + dateFormat.format(customerCfg.modifyTime));
		log.info("认购：" + dateFormat.format(orderCfg.beginTime));
		log.info("签约：" + dateFormat.format(contractCfg.beginTime));
		log.info("认筹：" + dateFormat.format(bookingCfg.beginTime));
		log.info("款项：" + dateFormat.format(getinCfg.beginTime));
		log.info("机会：" + dateFormat.format(opportunityCfg.beginTime));
		log.info("跟进：" + dateFormat.format(receiveCfg.beginTime));
		log.info("会员：" + dateFormat.format(memberCfg.beginTime));
		log.info("积分：" + dateFormat.format(pointCfg.beginTime));

		log.info(C.SPLIT_LINE);
	} // ~loadConfig

	private void parseSyncTime() throws Exception {
		String s = Cfg.get("sync.begin");
		int[] ts;
		if ((ts = parseSyncTime(s)) == null) {
			log.error("parse sync begin time [" + s + "] fail!");
			return;
		}
		AvoidDisturb.setBegin(ts[0], ts[1]);

		ts = null;
		s = Cfg.get("sync.end");
		if ((ts = parseSyncTime(s)) == null) {
			log.error("parse sync end time [" + s + "] fail!");
			return;
		}
		AvoidDisturb.setEnd(ts[0], ts[1]);
	}

	int[] parseSyncTime(String hm) throws Exception {
		int[] ts = { 0, 0 };
		try {
			String hstr = hm.substring(0, 2);
			int h = Integer.parseInt(hstr);
			if (h < 0 || h > 23) {
				return null;
			}

			String mstr = hm.substring(3);
			int m = Integer.parseInt(mstr);
			if (m < 0 || h > 59) {
				return null;
			}
			ts[0] = h;
			ts[1] = m;
			return ts;
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	Date parseTime(String s) {
		try {
			return new Date(dateFormat.parse(s).getTime());
		} catch (Exception e) {
			return null;
		}
	}

	public void sync() {
	}
	
	private final void singleSync(String sync) {
		printInfo();
		loadConfig(); // 加载最后一次同步的数据时间，也就是首次增量时的时间

		if ("cst".equals(sync)) {
			new CustomerSync().sync();
		} else if ("recv".equals(sync)) {
			new ReceiveSync().sync(); // 跟进记录
		} else if ("booking".equals(sync)) {
			new BookingSync().sync(); // 认筹
		} else if ("order".equals(sync)) {
			new OrderSync().sync(); // 认购
		} else if ("contract".equals(sync)) {
			new ContractSync().sync(); // 签约
		} else if ("mystation".equals(sync)) {
			new MyStationSync().sync(); //
		} else if ("mystationuser".equals(sync)) {
			new MyStationUserSync().sync(); //
		} else if ("myuser".equals(sync)) {
			new MyUserSync().sync(); //
		} else if ("member".equals(sync)) {
			new MemberSync().sync(); // 会员
		} else if ("room".equals(sync)) {
			new RoomSync().sync(); // 房产
		} else if ("proj".equals(sync)) {
			new ProjectSync().sync(); // 项目
		} else if ("areabu".equals(sync)) {
			new AreaCompanySync().sync(); // 区域公司
		} else if ("ekbu".equals(sync)) {
			new CompanySync().sync(); // 公司
		} else if ("poin".equals(sync)) {
			new HpointSync().sync(); // 会员积分
		} else if ("building".equals(sync)) {
			new BuildingSync().sync(); // 楼栋
		} else if ("saleserviceproc".equals(sync)) {
			new SaleServiceProcSync().sync(); //
		} else if ("bizparam".equals(sync)) {
			new BizParamOptionSync().sync(); //
		} else if ("cqserviceproc".equals(sync)) {
			new CqServiceProcSync().sync(); //
		} else if ("cqservice".equals(sync)) {
			new CqServiceSync().sync(); //
		} else if ("fee".equals(sync)) {
			new FeeSync().sync(); //
		} else if ("saleservice".equals(sync)) {
			new SaleServicetSync().sync(); //
		} else if ("cstattach".equals(sync)) {
			new CstAttachSync().sync(); //
		} else if ("opp".equals(sync)) {
			new OpportunitySync().sync(); //
		} else if ("getin".equals(sync)) {
			new GetInSync().sync();
		} else {
			String[][] syncs={
					{"cst","客户"},
					{"opp","机会"},
					{"recv","跟进"},
					{"booking","认筹"},
					{"order","认购"},
					{"contract","签约"},
					{"getin","回款"},
					{"mystation","职位"},
					{"mystationuser","置业顾问职位"},
					{"myuser","职业顾问"},
					{"cstattach","客户特征"},
					{"member","会员"},
					{"poin","会员积分"},
					{"areabu","区域公司"},
					{"ekbu","公司"},
					{"proj","项目"},
					{"building","楼栋"},
					{"room","房产"},
					{"saleserviceproc","销售服务过程"},
					{"saleservice","销售服务"},
					{"bizparam","业务参数"},
					{"fee","欠款"},
					{"cqserviceproc","产权服务过程"},
					{"cqservice","产权服务"}
			};
			System.out.println("unkonw sync:" + sync);
			for (String[] s : syncs) {
				System.out.println(String.format("%-16s: %s", s[0], s[1]));
			}
		}
	}


	private final void doSync() {
		if (MonitorClient.isModuleRunning(C.DC_MODULE_KEY)) {
			log.warn("模块实例正在运行中.");
			return;
		}
		module = getModule("DC.SYNC");
		if (module == null) {
			log.error("获取模块信息失败，无法监控模块");
		} else {
			MonitorClient.start(module);
		}

		printInfo();
		monitorLog("初始化系统配置");
		loadConfig(); // 加载最后一次同步的数据时间，也就是首次增量时的时间

		monitorLog("清除客户锁");
		LockContext.clearLocks();

		monitorLog("启动接口服务");
		startApiServer();
		monitorLog("启动每日同步");
		startDailySync();
		monitorLog("启动定时同步");
		startIntimeSync();
	} // ~sync

	/* 启动API服务 */
	protected void startApiServer() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					String portStr = Cfg.get("server.api.port");
					int port = Integer.parseInt(portStr);
					log.info(String.format("API服务[端口：%s]", port));
					apiServer.listen(port);
					log.info("API服务已启动!");
				} catch (Exception e) {
					e.printStackTrace();
					log.error("启动API服务失败：" + e);
				}
			}
		}).start();
	} //~startApiServer

	/* 启动每日同步 */
	protected void startDailySync() {
		final List<AgentSync> syncs = new ArrayList<AgentSync>();
		AgentSync sync = new MemberSync();
		sync.setSyncLabel("会员");
		syncs.add(sync);

		sync = new HpointSync();
		sync.setSyncLabel("会员积分");
		syncs.add(sync);

		sync = new BuildingSync();
		sync.setSyncLabel("楼栋");
		syncs.add(sync);

		sync = new RoomSync();
		sync.setSyncLabel("房产");
		syncs.add(sync);

		sync = new ProjectSync();
		sync.setSyncLabel("项目");
		syncs.add(sync);

		sync = new AreaCompanySync();
		sync.setSyncLabel("区域公司");
		syncs.add(sync);

		sync = new CompanySync();
		sync.setSyncLabel("公司");
		syncs.add(sync);

		sync = new EmpInfoSync();
		sync.setSyncLabel("员工");
		syncs.add(sync);

		sync = new GetInSync();
		sync.setSyncLabel("回款");
		syncs.add(sync);

		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					// 检查是否需要休眠等待
					AvoidDisturb.checkAndWait(0);
					if (pause) { // 如果中断，休眠3秒继续等待
						sleep(3000);
						continue;
					}
					monitorLog("开始每日同步");
					for (final AgentSync sync : syncs) {
						try {
							// 等待结束，进行同步
							sync.monitorLog("开始同步");
							sync.sync();
							sync.monitorLog("同步完成");
						} catch (Exception e) {
							String exInfo = Util.formatStackTrace(e);
							sync.monitorLog("同步异常：" + exInfo);
							log.error(exInfo);
						}
					}
					log.info("每日同步完成");
					monitorLog("每日同步完成");
					sleep(5 * 3600 * 1000); // 休眠5小时
				}
			}
		}).start();
	} //~startDailySync

	/* 每小时同步 */
	protected void startIntimeSync() {
		final List<AgentSync> intimeSyncs = new ArrayList<AgentSync>();
		AgentSync sync = new CustomerSync();
		sync.setSyncLabel("客户");
		intimeSyncs.add(sync);

		sync = new ReceiveSync();
		sync.setSyncLabel("跟进记录");
		intimeSyncs.add(sync);

		sync = new BookingSync();
		sync.setSyncLabel("认筹");
		intimeSyncs.add(sync);

		sync = new OrderSync();
		sync.setSyncLabel("认购");
		intimeSyncs.add(sync);

		sync = new ContractSync();
		sync.setSyncLabel("签约");
		intimeSyncs.add(sync);
		
		sync = new OpportunitySync();
		sync.setSyncLabel("销售机会");
		intimeSyncs.add(sync);

		sync = new MyUserSync();
		sync.setSyncLabel("置业顾问用户");
		intimeSyncs.add(sync);

		sync = new MyStationSync();
		sync.setSyncLabel("用户职位");
		intimeSyncs.add(sync);

		sync = new MyStationUserSync();
		sync.setSyncLabel("用户职位关联表");
		intimeSyncs.add(sync);

		new Thread(new Runnable() {
			@Override
			public void run() {
				int lastDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
				while (true) {
					
					rebackOffset = BACK_HOURS; // 三小时
					Calendar cal = Calendar.getInstance();
					int hour = cal.get(Calendar.HOUR_OF_DAY);
					if (hour == 4 || hour == 5) {
						int day = cal.get(Calendar.DAY_OF_MONTH);
						if (day != lastDay) {
							rebackOffset = BACK_DAYS; // 三天
							lastDay = day;
						}
					}
					String msg = "开始同步，同步回溯 " + rebackOffset / 60 + "小时";
					log.info(msg);
					monitorLog(msg);
					long now = System.currentTimeMillis();
					for (final AgentSync sync : intimeSyncs) {
						if (pause) {
							log.info("程序中断同步");
							if (sync instanceof CustomerSync) {
								sync.monitorLog("开始同步");
								sync.sync();
								sync.monitorLog("同步完成");
							}
							continue;
						} // end if
						try {
							// 等待结束，进行同步
							sync.monitorLog("开始同步");
							sync.sync();
							sync.monitorLog("同步完成");
						} catch (Exception e) {
							String exInfo = Util.formatStackTrace(e);
							sync.monitorLog("同步异常：" + exInfo);
							log.error(exInfo);
						}
					} // end for
					log.info("sync intime once");
					monitorLog("完成一次定时同步");
					now = System.currentTimeMillis() - now;
					long offset = intervalIntime - now;
					sleep(offset < 0 ? 10 : offset);
				}
			}
		}).start();
	} //~startIntimeSync

	void sleep(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/*
	 * 取房产信息
	 */
	protected RoomInfo getRoomInfo(Connection con, String roomGUID) {
		RoomInfo roomInfo = new RoomInfo();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			String sql = "select Room,HuXing from p_Room where RoomGUID=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, roomGUID);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				roomInfo.setRoomGUID(roomGUID);
				roomInfo.setRoom(rs.getString(1));
				roomInfo.setHuxing(rs.getString(2));
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("query room info error: " + e);
		} finally {
			ADataSource.close(rs, pstmt, null);
		}
		return roomInfo;
	} //~getRoomInfo

	public String getSyncLabel() {
		return syncLabel;
	}

	public void setSyncLabel(String syncLabel) {
		this.syncLabel = syncLabel;
	}

	public void monitorLog(String msg) {
		monitorLog(C.LOG_LEVEL_INFO, msg);
	}

	public void monitorLog(String level, String msg) {
		writeMonitorLog(level, getSyncLabel(), msg);
	}
} // /~
